package ast.statement.select

import ast.expr.SqlBinaryExpr
import ast.expr.SqlBinaryOperator
import ast.expr.SqlExpr
import ast.expr.SqlIdentifierExpr
import ast.limit.SqlLimit
import ast.order.SqlOrderBy
import ast.statement.SqlStatement
import ast.table.SqlTableSource

sealed class SqlSelectQuery : SqlStatement

data class SqlSelect(
    var distinct: Boolean = false,
    val selectList: MutableList<SqlSelectItem> = mutableListOf(),
    var from: SqlTableSource? = null,
    var where: SqlExpr? = null,
    val groupBy: MutableList<SqlExpr> = mutableListOf(),
    val orderBy: MutableList<SqlOrderBy> = mutableListOf(),
    var forUpdate: Boolean = false,
    var limit: SqlLimit? = null,
    var having: SqlExpr? = null
) : SqlSelectQuery() {
    fun addSelectItem(expr: SqlExpr, alias: String? = null) {
        selectList.add(SqlSelectItem(expr, alias))
    }

    fun addSelectItem(column: String, alias: String? = null) {
        selectList.add(SqlSelectItem(SqlIdentifierExpr(column), alias))
    }

    fun addCondition(condition: SqlExpr) {
        where = if (where != null) {
            SqlBinaryExpr(where!!, SqlBinaryOperator.AND, condition)
        } else {
            condition
        }
    }

    fun addHaving(condition: SqlExpr) {
        having = if (having != null) {
            SqlBinaryExpr(having!!, SqlBinaryOperator.AND, condition)
        } else {
            condition
        }
    }
}

data class SqlUnionSelect(val left: SqlSelectQuery, val type: SqlUnionType, val right: SqlSelectQuery) :
    SqlSelectQuery()

data class SqlWithSelect(
    val with: MutableList<SqlWithItem> = mutableListOf(),
    var recursive: Boolean = false,
    var query: SqlSelectQuery? = null
) : SqlSelectQuery()

data class SqlValuesSelect(val values: MutableList<List<SqlExpr>> = mutableListOf()) : SqlSelectQuery()